using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using Frogger_Input;

// ****************************************************************************** //
//   This component handles the rendering of all the 3d elements in the game      //
// ****************************************************************************** //

namespace Frogger_Game
{
    /// <summary>
    /// Game component that implements IUpdateable.
    /// </summary>
    public class Rendering3D : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public Rendering3D(Game game)
            : base(game)
        {
        }

        //3d models
        Model frogtext;
        Model carstext1;
        Model carstext2;
        Model carstext3;
        Model carstext4;
        Model trunkmod1;
        Model trunkmod2;
        Model leafmod1;
        Model leafmod2;
        Model[] frogwin = new Model[5];

        //shared basic effect
        BasicEffect basic_effect;

        //cars textures
        Texture2D turquaz;
        Texture2D silver;
        Texture2D golden;
        Texture2D red;

        //some constant rotations
        float MODELROTATIONY = -110.0f;
        float MODELROTATIONX = 0f;

        // Set the position of the camera in world space, for our view matrix.
        Vector3 cameraPosition = new Vector3(0.0f, 20.0f, 50.0f);

        /// <summary>
        /// Initialize non-graphics content
        /// </summary>
        ///
        public override void Initialize()
        {
            base.Initialize();
        }

        /// <summary>
        /// Load graphics content
        /// </summary>
        protected override void LoadContent()
        {
            //DebugShapeRenderer.Initialize(GraphicsDevice); // DEBUG

            //load 3d models
            frogtext = Game.Content.Load<Model>("frog");
            carstext1 = Game.Content.Load<Model>("car1");
            carstext2 = Game.Content.Load<Model>("car2");
            carstext3 = Game.Content.Load<Model>("car3");
            carstext4 = Game.Content.Load<Model>("car4");
            trunkmod1 = Game.Content.Load<Model>("half_log_3");
            trunkmod2 = Game.Content.Load<Model>("half_log_2");
            leafmod1 = Game.Content.Load<Model>("waterlily3");
            leafmod2 = Game.Content.Load<Model>("waterlily3");
            turquaz = Game.Content.Load<Texture2D>("CarsTextures/turquaz");
            silver = Game.Content.Load<Texture2D>("CarsTextures/silver");
            red = Game.Content.Load<Texture2D>("CarsTextures/red");
            golden = Game.Content.Load<Texture2D>("CarsTextures/golden");
            frogwin[0] = frogwin[1] = frogwin[2] = frogwin[3] = frogwin[4] = Game.Content.Load<Model>("frog");
            
            //frustum generic settings
            basic_effect = new BasicEffect(GraphicsDevice);
            basic_effect.View = Matrix.CreateLookAt(cameraPosition,
                Vector3.Zero, Vector3.Up);
            basic_effect.Projection = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45.0f), GraphicsDevice.Viewport.AspectRatio,
                1.0f, 100.0f);

            base.LoadContent();
        }


        /// <summary>
        /// Draw method
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Draw(GameTime gameTime)
        {
            //we do not draw 3d models if the game is in pause
            if (!Game1.isPaused)
            {
                #region frog rendering

                Matrix[] transforms = new Matrix[frogtext.Bones.Count];
                frogtext.CopyAbsoluteBoneTransformsTo(transforms);
                foreach (var mesh in frogtext.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        var modelPosition = new Vector3(FrogTypes.frog_state.PositionX.Value, FrogTypes.frog_state.PositionY.Value, FrogTypes.frog_state.PositionZ.Value);
                        effect.GraphicsDevice.BlendState = BlendState.Opaque;
                        effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                        effect.EnableDefaultLighting();
                        effect.World = transforms[mesh.ParentBone.Index]
                            * Matrix.CreateRotationY(MODELROTATIONY)
                            * Matrix.CreateRotationY(FrogTypes.frog_state.RotationY.Value * (float)System.Math.PI / 180)
                            * Matrix.CreateRotationX(MODELROTATIONX)
                            * Matrix.CreateTranslation(modelPosition);
                        effect.View = basic_effect.View;
                        effect.Projection = basic_effect.Projection;
                    }
                    mesh.Draw();
                }

                #endregion

                if (!Game1.isWaiting)
                {

                #region cars rendering
                Matrix[] transforms_car = new Matrix[carstext1.Bones.Count];
                carstext1.CopyAbsoluteBoneTransformsTo(transforms_car);

                foreach (var a in CarsTypes.cars_state.Cars.Value)
                {
                    foreach (var mesh in carstext1.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.Texture = red;
                            effect.World = transforms_car[mesh.ParentBone.Index]
                                * Matrix.CreateRotationY(MODELROTATIONY)
                                * Matrix.CreateRotationX(MODELROTATIONX)
                                * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }
                }


                foreach (var a in CarsTypes.cars_state.Cars2.Value)
                {
                    foreach (var mesh in carstext2.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.Texture = silver;
                            effect.World = transforms_car[mesh.ParentBone.Index]
                                * Matrix.CreateRotationY(MODELROTATIONY)
                                * Matrix.CreateRotationX(MODELROTATIONX)
                                * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }
                }

                foreach (var a in CarsTypes.cars_state.Cars3.Value)
                {
                    foreach (var mesh in carstext3.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.Texture = golden;
                            effect.World = transforms_car[mesh.ParentBone.Index]
                                * Matrix.CreateRotationY(0.0f)
                                * Matrix.CreateRotationX(MODELROTATIONX)
                                * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }
                }


                foreach (var a in CarsTypes.cars_state.Cars4.Value)
                {
                    foreach (var mesh in carstext4.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.Texture = turquaz;
                            effect.World = transforms_car[mesh.ParentBone.Index]
                                * Matrix.CreateRotationY(0.0f)
                                * Matrix.CreateRotationX(MODELROTATIONX)
                                * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }

                }

                #endregion

                #region trunks rendering

                Matrix[] transforms_trunk = new Matrix[trunkmod1.Bones.Count];
                trunkmod1.CopyAbsoluteBoneTransformsTo(transforms_trunk);

                foreach (var a in RiverTypes.river_state.Trunks1.Value)
                {
                    foreach (var mesh in trunkmod1.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.World = transforms_trunk[mesh.ParentBone.Index]
                               * Matrix.CreateRotationY(MODELROTATIONY)
                               * Matrix.CreateRotationX(MODELROTATIONX)
                               * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }
                }


                Matrix[] transforms_trunk2 = new Matrix[trunkmod2.Bones.Count];
                trunkmod2.CopyAbsoluteBoneTransformsTo(transforms_trunk2);

                foreach (var a in RiverTypes.river_state.Trunks2.Value)
                {
                    foreach (var mesh in trunkmod2.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.World = transforms_trunk2[mesh.ParentBone.Index]
                                * mesh.ParentBone.Transform
                                * Matrix.CreateRotationY(MODELROTATIONY)
                                * Matrix.CreateRotationX(MODELROTATIONX)
                                * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }
                }

                #endregion

                #region waterlily rendering

                foreach (var a in RiverTypes.river_state.Leaf1.Value)
                {
                    foreach (var mesh in leafmod1.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.World = mesh.ParentBone.Transform
                                * Matrix.CreateRotationX(421 * (float)System.Math.PI / 180)
                                * Matrix.CreateRotationY(76 * (float)System.Math.PI / 180)
                                * Matrix.CreateRotationZ(159 * (float)System.Math.PI / 180)
                                * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }
                }

                foreach (var a in RiverTypes.river_state.Leaf2.Value)
                {
                    foreach (var mesh in leafmod2.Meshes)
                    {
                        foreach (BasicEffect effect in mesh.Effects)
                        {
                            effect.GraphicsDevice.BlendState = BlendState.Opaque;
                            effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                            effect.EnableDefaultLighting();
                            effect.World = mesh.ParentBone.Transform
                                * Matrix.CreateRotationX(421 * (float)System.Math.PI / 180)
                                * Matrix.CreateRotationY(76 * (float)System.Math.PI / 180)
                                * Matrix.CreateRotationZ(159 * (float)System.Math.PI / 180)
                                * Matrix.CreateTranslation(new Vector3(a.PositionX.Value, a.PositionY.Value, a.PositionZ.Value));
                            effect.View = basic_effect.View;
                            effect.Projection = basic_effect.Projection;
                        }

                        mesh.Draw();
                    }
                }

                #endregion


                #region victory frogs rendering
                for (int n = 0; n < 5; n++)
                {
                    if (GameState.game_state.winbox_check[n] == true)
                    {
                        Matrix[] transformf = new Matrix[frogwin[n].Bones.Count];
                        frogwin[n].CopyAbsoluteBoneTransformsTo(transforms);
                        foreach (var mesh in frogwin[n].Meshes)
                        {
                            foreach (BasicEffect effect in mesh.Effects)
                            {
                                var modelPosition = new Vector3((MapGrid.win_boxes[n].Item1 + MapGrid.win_boxes[n].Item2) / 2, MapGrid.WIN_Y, MapGrid.WIN_Z);
                                
                                //for a realistic effect, here we are using orthographic projection
                                effect.GraphicsDevice.BlendState = BlendState.Opaque;
                                effect.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
                                effect.EnableDefaultLighting();
                                effect.World = transforms[mesh.ParentBone.Index]
                                    * Matrix.CreateRotationY(MODELROTATIONY)
                                    * Matrix.CreateTranslation(modelPosition);
                                Vector3 cam = new Vector3(0.0f, 1.0f, 40.0f);
                                effect.View = basic_effect.View;
                                effect.Projection = Matrix.CreateOrthographic(80 * ((float)this.GraphicsDevice.Viewport.AspectRatio / 1.7786f), 47, 1 * ((float)this.GraphicsDevice.Viewport.AspectRatio / 1.7786f), 90 * ((float)this.GraphicsDevice.Viewport.AspectRatio / 1.7786f));
                            }
                            mesh.Draw();
                        }
                    }
                }

                #endregion

                }
            }

            #region [Debug] boundingbox
            //foreach (var car in CarsTypes.cars_state.Cars.Value)
            //{

            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)car.box, Color.Red);
            //}

            //foreach (var car in CarsTypes.cars_state.Cars2.Value)
            //{

            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)car.box, Color.Red);
            //}

            //foreach (var car in CarsTypes.cars_state.Cars3.Value)
            //{
            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)car.box, Color.Red);
            //}

            //foreach (var car in CarsTypes.cars_state.Cars4.Value)
            //{
            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)car.box, Color.Red);
            //}

            //foreach (var trunk in RiverTypes.river_state.Trunks1.Value)
            //{
            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)trunk.box, Color.Red);
            //}

            //foreach (var trunk in RiverTypes.river_state.Trunks2.Value)
            //{
            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)trunk.box, Color.Red);
            //}

            //foreach (var leaf in RiverTypes.river_state.Leaf1.Value)
            //{
            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)leaf.box, Color.Red);
            //}

            //foreach (var leaf in RiverTypes.river_state.Leaf2.Value)
            //{
            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)leaf.box, Color.Red);
            //}

            //foreach (var box in MapGrid.win_boxes)
            //{
            //    BoundingBox b = new BoundingBox(new Vector3(box.Item1, MapGrid.WIN_Y - 2.0f, MapGrid.WIN_Z + 2.0f), new Vector3(box.Item2, MapGrid.WIN_Y + 2.0f, MapGrid.WIN_Z - 2.0f));              
            //    DebugShapeRenderer.AddBoundingBox((BoundingBox)b, Color.Red);
            //}

            //DebugShapeRenderer.AddBoundingSphere(FrogTypes.frog_state.sphere, Color.Blue);

            //DebugShapeRenderer.Draw(gameTime, Matrix.CreateLookAt(cameraPosition,
            //  Vector3.Zero, Vector3.Up), Matrix.CreatePerspectiveFieldOfView(
            //  MathHelper.ToRadians(45.0f), GraphicsDevice.Viewport.AspectRatio,
            //  1.0f, 100.0f));

            #endregion

            base.Draw(gameTime);
    }


    }
}
